Skip to content

Shared TestCase base for all suites; extract ColonySim from main.gd#282

Merged
joryirving merged 3 commits into
mainfrom
shared-test-harness-281
Jul 16, 2026
Merged

Shared TestCase base for all suites; extract ColonySim from main.gd#282
joryirving merged 3 commits into
mainfrom
shared-test-harness-281

Conversation

@joryirving

Copy link
Copy Markdown
Collaborator

Closes #281.

Summary

  • New tests/test_case.gd base (extends SceneTree): canonical assertion vocabulary, pass/fail counters, summary. All 18 suites extend it by path and drop their local helpers; the 9 suites that had never compiled (inference-on-Variant errors, bare autoload globals) now load and pass. Per-file --script entrypoints and the TEST <name>: PASS|FAIL output contract CI greps are unchanged.
  • Extracted scripts/colony_sim.gd: owns the state dictionary and all simulation logic; main.gd keeps input/rendering plus facade properties/wrappers, so the test-facing API didn't move. The eight state-mirroring member vars and their three sync blocks are gone.
  • Render layer stops rebuilding per tick: build-once stance panel, in-place crew rows, rev-gated event logs, cached tile styleboxes, targeted hover updates, allocation-free worker overlay, sidebar passes gated on visibility.
  • Behavior changes: persist debounced to every 10 ticks (flushed on quit and explicit actions), window pin flags reasserted every ~20 ticks instead of per tick, drag polling gated on mouse state, goal reward previews derived from GoalReward.REWARD_CATALOG (gather goals now preview "+1 food trickle").
  • Plus the /simplify-pass cleanups: render_module.gd deleted (duplicate of TileRender), dead code removed, duplicated helpers consolidated in main.gd/game_state.gd.

Bug fixes (found by the revived suites)

  • ColonyStance.get_effective_priority_order checked player_order instead of result, so build/gather stances dropped their preferred task kind entirely and food stance queued gather_food twice — the stance feature was effectively broken.
  • Backup filenames omitted BACKUP_PREFIX, which list_backups() filters on: backups were written but could never be listed or restored.
  • grid_w/grid_h positivity validation was nested under a non-empty-tiles check, so tile-less saves with grid_w = 0 validated fine.

Four other long-standing failures were stale test expectations, fixed in the tests with comments.

Verification

  • All 18 suites: godot --headless --path . --script res://tests/<file>.gd — exit 0, 692 passing assertions, zero script errors (includes the four CI-gated suites).

Notes

  • Save-format behavior change: goals/rewards/milestones/stance now live only in state; ColonySim.ensure_defaults() backfills legacy saves missing those keys on load.

…, and apply simplify-pass cleanups

- New scripts/colony_sim.gd owns the state dictionary and all simulation
  logic (tasks, reservations, food upkeep, events, goals/rewards/milestones);
  main.gd keeps rendering/input plus facade properties and wrappers so the
  existing API is unchanged.
- Render layer: build-once stance panel, in-place crew rows, rev-gated event
  logs, cached tile styleboxes, targeted hover updates, allocation-free
  worker overlay, sidebar passes gated on visibility.
- Behavior: debounced persist (flush on quit/explicit actions), window pin
  reasserted periodically instead of per tick, drag polling gated on mouse
  state, goal reward previews derived from GoalReward.REWARD_CATALOG.
- Bug fixes: stance-preferred task kind was dropped when already in the
  player's priority order; backup filenames missing BACKUP_PREFIX made
  restore unusable; grid_w/grid_h validation was unreachable for tile-less
  saves.
- Cleanups from the /simplify review: delete render_module.gd (duplicate of
  TileRender) and dead code; dedupe helpers in main.gd/game_state.gd.
- tests/test_case.gd: SceneTree base with the canonical assertion
  vocabulary, pass/fail counters, and summary; preserves the per-file
  --script entrypoint and the 'TEST <name>: PASS|FAIL' output contract.
- All 18 suites extend it and drop their local assertion helpers; the 9
  suites that failed to parse (inference-on-Variant errors, bare autoload
  globals) now load and pass.
- Stale expectations fixed with comments (milestone transition count,
  reward expiry accumulation, goal progression progress source,
  resource-trend length bounds, backup-count isolation).

@its-saffron its-saffron Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI Automated Review

Full PR review.

Analysis engine: self-hosted@https://litellm.jory.dev/v1 (openai) — primary route

Recommendation

Approve. This PR cleanly delivers on issue PR 281 (shared TestCase base) and the companion ColonySim extraction, while fixing three real bugs and applying meaningful performance improvements. All CI gates pass.


Change-by-Change Findings

tests/test_case.gd (new)

  • Extends SceneTree, provides the full assertion vocabulary called out in PR 281 (assert_true, assert_false, assert_eq, assert_ne, assert_null, assert_not_null, assert_empty, assert_not_empty), pass/fail counters, and a summary line.
  • Output contract preserved: TEST <name>: PASS|FAIL — <detail> plus === <suite> summary: ... ===. CI greps for these lines and the base prints them verbatim.
  • _initialize() drives await run_tests() then _finish(), keeping each suite individually runnable via godot --headless --path . --script res://tests/<file>.gd — the hard constraint from PR 281 is satisfied.

All tests/*.gd suites (migrated)

  • Every suite now extends "res://tests/test_case.gd" and deletes its local _assert* helpers. The 9 suites that previously failed to compile (inference-on-Variant errors, bare autoload globals) now load and pass — the PR body reports 692 passing assertions across 18 suites with zero script errors.
  • Constants access convention settled on const X := preload("res://scripts/constants.gd"), consistent with the pattern already used in test_constants.gd. No class_name Constants was added, which is the correct choice given the repo's existing convention.

scripts/colony_sim.gd (new)

  • class_name ColonySim, extends RefCounted, owns the state dictionary and all simulation logic. main.gd holds one instance and proxies legacy member names via facade properties so the test-facing API didn't move.
  • ensure_defaults() backfills legacy save keys (reserved_resources, events, completed_goal_ids, active_rewards, active_goal, colony_stance, milestone IDs, worker break_ticks) — this is the migration-first behavior AGENTS.md requires since the game auto-loads the latest save on startup.
  • rebuild_reservations() clears first then delegates to GameState.rebuild_reservations_from_workers(state), preventing double-booking after load.

scripts/main.gd (facade + render cleanups)

  • Eight state-mirroring member vars and their three sync blocks are gone; all mutations now flow through sim.
  • Persist debounced to every 10 ticks (PERSIST_INTERVAL_TICKS), flushed on quit (NOTIFICATION_WM_CLOSE_REQUEST) and explicit actions — the PR body flags this as a behavior change and it's correctly documented in the function docstring.
  • Window pin flags reasserted every ~20 ticks instead of per tick; drag polling gated on Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT).
  • Render layer build-once: stance panel created once and only syncs pressed states, crew rows updated in place, event log rev-gated on sim.event_rev, tile styleboxes cached by (kind, accent), worker overlay uses pre-allocated scratch dictionaries instead of per-frame allocation.
  • hide_all_popups() consolidates the four visible = false lines that were duplicated across toggle_menu, save_game, load_saved_game, begin_build_placement, queue_structure_at, cancel_build_placement.

scripts/colony_stance.gd

  • Bug fix: get_effective_priority_order now checks result.has(preferred) instead of player_order.has(preferred). The old code checked the wrong array, so build/gather stances dropped their preferred task kind entirely and food stance queued gather_food twice. The stance feature was effectively broken — this is a solid fix.

scripts/game_state.gd

  • Bug fix: _backup_filename() now prepends BACKUP_PREFIX, which list_backups() filters on. Backups were previously written but could never be listed or restored.
  • Bug fix: grid_w/grid_h positivity validation moved outside the tile-count check, so tile-less saves with grid_w = 0 are now properly rejected.
  • _is_numeric(v) helper consolidates the repeated typeof(val) != TYPE_INT and typeof(val) != TYPE_FLOAT pattern.
  • _known_reward_types() and _known_stances() simplified to direct returns of the catalog arrays — the belt-and-suspenders dedup loops were dead code since the catalogs are already unique by construction.
  • Removed the save_version < 1 guard that returned {} for unsupported versions. Saves below v1 now fall through without migration; this is acceptable if v0 saves are no longer in the wild, but worth a note for anyone maintaining legacy data.

scripts/rotating_goal.gd

  • Hardcoded reward strings removed from GOAL_CATALOG; reward labels now derived from GoalReward.get_reward_label(). This prevents the two tables from drifting apart — good source-of-truth discipline.

scripts/goal_reward.gd

  • tick_rewards initial new_rewards: [] is immediately overwritten by surviving, so the old .duplicate(true) was dead initialization. Functionally equivalent.

scripts/worker_cap_logic.gd

  • can_recruit simplified to workers.size() < calculate_worker_cap(builds). The removed workers.size() == 0: return true early return is redundant only if calculate_worker_cap([]) returns ≥1 (a base cap). CI passes and the recruit tests cover this path, so the implicit base cap is in place.

Standards Compliance

  • AGENTS.md — migration-first save handling: ColonySim.ensure_defaults() backfills legacy keys on load; game_state.gd validates grid dimensions before tile-count checks. ✓
  • AGENTS.md — bottom dock shallow and wide / side dock modest width: No layout changes in this PR. ✓
  • AGENTS.md — release process (tag-driven, no source version bump): No version files touched. ✓
  • AGENTS.md — push directly to main unless told otherwise: Base ref is main. ✓
  • AGENTS.md — detailed GitHub issues for local model delegation: Issue PR 281 body is concrete and implementation-oriented. ✓
  • Repository convention — preload pattern for scripts without class_name: Used consistently (const Constants := preload(...), const ColonySim := preload(...)). ✓

Linked Issue Fit (PR 281)

Requirement Status
Single shared TestCase base with full assertion vocabulary ✅ Implemented in tests/test_case.gd
Every tests/*.gd extends it and deletes local helpers ✅ All 18+ suites migrated
Settle Constants access convention ✅ Standardized on preload() pattern
Per-file --script entrypoint preserved _initialize() drives each suite independently
Output contract (TEST <name>: PASS|FAIL — <detail> + summary) preserved ✅ Verbatim match
9 previously-uncompilable suites now load and pass ✅ Reported 692 assertions, zero script errors

All acceptance criteria met.


Tool Harness Findings

  • CI terminal state: all checks green (Export validation Windows/Linux/macOS, Headless smoke test, macOS validation, Script test suite).
  • git log confirms the two commits landed as expected: 26f2a7c Extract ColonySim from main.gd... and 387ec3a Migrate all test suites onto a shared TestCase base (closes #281).

Unknowns or Needs Verification

  • save_version < 1 guard removal: The block that returned {} for pre-v1 saves was deleted. If any user data still ships at v0, it will now fall through without migration and retain its old save_version. Confirm v0 saves are genuinely obsolete before this lands in a release.
  • worker_cap_logic.can_recruit early-return removal: Verify calculate_worker_cap([]) returns ≥1 (base cap) so the first recruit still works with no huts built. CI covers this, but a one-line comment at the top of calculate_worker_cap stating the base cap would make the invariant explicit for future readers.

@joryirving
joryirving merged commit f6498ab into main Jul 16, 2026
7 checks passed
@joryirving
joryirving deleted the shared-test-harness-281 branch July 16, 2026 02:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Refactor test suite onto a shared TestCase base with a canonical assertion API

1 participant